/*******************************************************************************
 * Copyright (c) 2012 Alexandr Tsvetkov.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v2.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     Alexandr Tsvetkov - initial API and implementation
 * 
 * Project:
 *     TAO Library
 * 
 * File name:
 *     TSoundPool.java
 *     
 * License agreement:
 *
 * 1. This code is published AS IS. Author is not responsible for any damage that can be
 *    caused by any application that uses this code.
 * 2. Author does not give a garantee, that this code is error free.
 * 3. This code can be used in NON-COMMERCIAL applications AS IS without any special
 *    permission from author.
 * 4. This code can be modified without any special permission from author IF AND ONLY IF
 *    this license agreement will remain unchanged.
 * 5. SPECIAL PERMISSION for this code usage in COMMERCIAL application SHOULD be obtained
 *    from author.
 ******************************************************************************/
package ua.at.tsvetkov.media;

import ua.at.tsvetkov.util.Log;

/**
 * @author A.Tsvetkov 2010 http://tsvetkov.at.ua mailto:al@ukr.net
 */
public class TSoundPool {

	public static final int			ADDITIONAL_TIME	= 50;
	private int							maxcount;
	private TMediaPlayer[]			players;
	private TSoundPoolHandler		tSoundPoolHandler;
	public static float				volume				= 1f;

	/**
	 * Создает пул плэйеров
	 */
	public TSoundPool() {
		this.maxcount = 0;
	}

	/**
	 * Создает пул плейеров указанного количеста для предварительной загрузки звуков и запускает обслуживание
	 * 
	 * @param count количество плейеров
	 * @param preloadTime приблизительное время нужное для загрузки самого большого файла, округлять в большую сторону.
	 */
	public void init(int count, long preloadTime) {
		if (maxcount > 0) {
			for (int i = 0; i < players.length; i++) {
				players[i].release();
			}
		}
		this.maxcount = count;
		players = new TMediaPlayer[maxcount];
		for (int i = 0; i < players.length; i++) {
			players[i] = new TMediaPlayer();
		}
		tSoundPoolHandler = new TSoundPoolHandler(players, preloadTime);
		new Thread(tSoundPoolHandler, "TSoundPool handler").start();
	}

	/**
	 * Добавляет звук из файла.
	 * 
	 * @param path путь к файлу
	 * @param timeBegin время начала звучания
	 * @return идентификатор если успешно, -1 если пул заполнен
	 */
	public int addSound(String path, long timeBegin) {
		// Проверяем на наличие готовых и загруженных звуков (увеличиваем их время жизни)
		for (int i = 0; i < players.length; i++) {
			if (players[i].resourceID.equals(path) && players[i].status == TMediaPlayer.READY) {
				if (players[i].timeBegin < timeBegin) {
					players[i].timeBegin = timeBegin;
					players[i].timeEnd = players[i].timeBegin + players[i].getDuration() + ADDITIONAL_TIME;
				}
				players[i].status = TMediaPlayer.READY;
				Log.v("Player " + i + " replay");
				return i;
			}
		}
		// Проверяем на наличие пустых плейеров
		for (int i = 0; i < players.length; i++) {
			if (players[i].status == TMediaPlayer.EMPTY) {
				players[i].resourceID = path;
				players[i].timeBegin = timeBegin;
				players[i].status = TMediaPlayer.NEED_TO_LOAD;
				// Log.v(tag + "addSound", "Player " + i + " new sound");
				return i;
			}
		}
		// Проверяем на наличие простаивающих
		for (int i = 0; i < players.length; i++) {
			if (players[i].status == TMediaPlayer.IDLE) {
				players[i].resourceID = path;
				players[i].timeBegin = timeBegin;
				players[i].status = TMediaPlayer.NEED_TO_LOAD;
				// Log.v(tag + "addSound", "Player " + i + " replased");
				return i;
			}
		}
		Log.w("Players is not free");
		return -1;
	}

	private void reSeek(final int id, boolean smoothly) {
		try {
			if (players[id].isPlaying()) {

				if (smoothly) {
					new Thread(new Runnable() {

						@Override
						public void run() {
							for (int i = 20; i >= 0; i--) {
								players[id].setVolume(i / 20f, i / 20f);
								try {
									Thread.sleep(10);
								} catch (InterruptedException e) {
									Log.wtf(e);
								}
							}
							if (players[id].isPlaying()) {
								players[id].pause();
								players[id].seekTo(0);
							}
							players[id].setVolume(1f, 1f);
						}
					}).start();
				} else {
					players[id].pause();
					players[id].seekTo(0);
				}

			}
		} catch (Exception e) {
			Log.w("sound pool reSeek error");
		}
	}

	/**
	 * Проигрывает звук
	 * 
	 * @param id
	 */
	public void play(final int id) {
		reSeek(id, false);
		players[id].setVolume(volume, volume);
		players[id].start();
	}

	public int getPosition(int id) {
		return players[id].getCurrentPosition();
	}

	public String getResource(int id) {
		return players[id].resourceID;
	}

	public void stop(int id) {
		reSeek(id, true);
	}

	public void stopAll() {
		for (int i = 0; i < players.length; i++) {
			reSeek(i, true);
		}
	}

	/**
	 * Освобождает все ресурсы
	 */
	public void release() {
		for (int i = 0; i < players.length; i++) {
			players[i].release();
		}
		tSoundPoolHandler.release();
	}
}
